package com.atguigu.comsumer;

import com.atguigu.constant.MqConst;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.SeckillProduct;
import com.atguigu.entity.UserSeckillSkuInfo;
import com.atguigu.service.SeckillProductService;
import com.atguigu.utils.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author ：Hachimen
 * @date ：Created in 2021/9/13 19:41
 * @description：
 * @modified By：
 * @version:
 */
@Component
public class SecKillConsumer {

    @Autowired
    private SeckillProductService seckillProductService;
    @Autowired
    private RedisTemplate redisTemplate;
    //1.扫描数据库中可以进行秒杀的商品
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.SCAN_SECKILL_QUEUE, durable = "false"),
              exchange = @Exchange(value = MqConst.SCAN_SECKILL_EXCHANGE, durable = "false"),
              key = {MqConst.SCAN_SECKILL_ROUTE_KEY}))
    public void scanSeckilProductToRedis(Message message, Channel channel) throws IOException {
        //a.扫描符合秒杀条件的商品
        QueryWrapper<SeckillProduct> wrapper = new QueryWrapper<>();
        //该商品状态为已审核通过
        wrapper.eq("status",1);
        //剩余库存>0
        wrapper.gt("stock_count",0);
        //取出该天日期的商品
        wrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
        List<SeckillProduct> seckillProductList = seckillProductService.list(wrapper);
        if(!CollectionUtils.isEmpty(seckillProductList)){
            for (SeckillProduct seckillProduct : seckillProductList) {
                //判断该秒杀商品是否在redis中已经存在
                Boolean aBoolean = redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).hasKey(seckillProduct.getSkuId().toString());
                if(aBoolean!=null&&aBoolean){
                    continue;
                }
                //b.把秒杀商品放入缓存redis
                redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).put(seckillProduct.getSkuId().toString(),seckillProduct);
                //c.利用list集合的数据结构存储商品剩余数量 减库存的时候从list取出一个 防止超卖
                for (Integer i = 0; i < seckillProduct.getNum(); i++) {
                    redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX+seckillProduct.getSkuId()).leftPush(seckillProduct.getSkuId().toString());
                }
                //d.还得通知redis集群中其他节点该商品可以进行秒杀啦
                redisTemplate.convertAndSend(RedisConst.PREPARE_PUB_SUB_SECKILL,seckillProduct.getSkuId()+":"+RedisConst.CAN_SECKILL);
            }
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

    }

    //2.预下单之后才能判断用户是否有抢购资格
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.PREPARE_SECKILL_QUEUE, durable = "false"),
            exchange = @Exchange(value = MqConst.PREPARE_SECKILL_EXCHANGE, durable = "false"),
            key = {MqConst.PREPARE_SECKILL_ROUTE_KEY}))
    public void prepareSeckill(UserSeckillSkuInfo userSeckillSkuInfo, Message message, Channel channel) throws IOException {
        seckillProductService.prepareSeckill(userSeckillSkuInfo);//预下单
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }


    //3.清理秒杀临时数据
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.CLEAR_REDIS_QUEUE, durable = "false"),
            exchange = @Exchange(value = MqConst.CLEAR_REDIS_EXCHANGE, durable = "false"),
            key = {MqConst.CLEAR_REDIS_ROUTE_KEY}))
    public void clearRedis(Message message, Channel channel) throws IOException {
        //a.扫描符合秒杀条件的商品
        QueryWrapper<SeckillProduct> wrapper = new QueryWrapper<>();
        //该商品状态为已审核通过
        wrapper.eq("status",1);
        //取出秒杀结束的商品
        wrapper.le("end_time",new Date());
        List<SeckillProduct> seckillProductList = seckillProductService.list(wrapper);
        if(!CollectionUtils.isEmpty(seckillProductList)){
            for (SeckillProduct seckillProduct : seckillProductList) {
                //删除库存数
                redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillProduct.getSkuId());
                //删除状态
                redisTemplate.delete(RedisConst.SECKILL_STATE_PREFIX+seckillProduct.getSkuId());
                //修改数据库中秒杀商品的状态
                seckillProduct.setStatus("2");
                seckillProductService.updateById(seckillProduct);
            }
            //删除商品信息
            redisTemplate.delete(RedisConst.SECKILL_PRODUCT);
            //删除订单信息
            redisTemplate.delete(RedisConst.PREPARE_SECKILL_USERID_ORDER);
            //删除最终抢到的订单信息
            redisTemplate.delete(RedisConst.BOUGHT_SECKILL_USER_ORDER);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

    }



}
